iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
Mobile Development

Android 從零開始系列 第 22

[Day22] ScrollView和SeekBar搭配應用

  • 分享至 

  • xImage
  •  

上次的幾篇文章中有教過ScrollView和SeekBar的基礎應用,讓大家對這兩個元件有一個基本的了解。這次我們就要結合這兩個元件做出一個可利用旁邊拉桿做拖拉的ScrollView。

JAVA程式碼

這次跟以前不一樣,我們要先寫JAVA的部分,對ScrollView和SeekBar做覆寫等等UI設計時才能使用。

ScrollView

創建一個名為ObservableScrollView的Class引用ScrollView並做重寫

public class ObservableScrollView extends ScrollView {
    public ScrollViewListener scrollViewListener = null;
    public ObservableScrollView (Context context) {
        super(context);
    }
    public ObservableScrollView (Context context, AttributeSet attrs,
                                 int defStyle) {
        super(context, attrs, defStyle);
    }
    public interface ScrollViewListener {
        void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);
    }
    public ObservableScrollView (Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }
    @Override
    public void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if (scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }
}

SeekBar

創建一個名為VerticalSeekbar的Class引用SeekBar並做重寫

public class VerticalSeekbar extends SeekBar {
    public VerticalSeekbar(Context context) {
        super(context);
    }
    public VerticalSeekbar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    public VerticalSeekbar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw);
    }
    @Override
    public synchronized void setProgress(int progress) // it is necessary for calling setProgress on click of a button
    {
        super.setProgress(progress);
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }
    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }
    protected void onDraw(Canvas c) {
        c.rotate(90);//旋轉
        c.translate(0, -getWidth());//旋轉,這兩行不可去掉
        super.onDraw(c);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
                setProgress((int) (getMax() * event.getY() / getHeight()));
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return true;
    }
}

ScrollBindHelper

創建一個名為ScrollBindHelper的Class,用來連結剛剛所創建的ScrollView和SeekBar,其功能主要為將SeekBar拖動的百分比換算並對應到ScrollView,但它還需要兩個工具的輔助,等等一樣會寫在下面。

public class ScrollBindHelper implements SeekBar.OnSeekBarChangeListener,ObservableScrollView.ScrollViewListener{
    private final VerticalSeekbar seekBar;
    private final ObservableScrollView scrollView;
    private final View scrollContent;
    /**
     * 使用靜態方法來繫結邏輯,程式碼可讀性更高。
     */
    public ScrollBindHelper(VerticalSeekbar seekBar, ObservableScrollView scrollView) {
        this.seekBar = seekBar;
        this.scrollView = scrollView;
        this.scrollContent = scrollView.getChildAt(0);
    }
    private boolean isUserSeeking;
    private int getContentRange() {
        seekBar.setMax(scrollContent.getHeight() - scrollView.getHeight());
        int Range=scrollView.getScrollY();
        return Range;
    }
    private int getScrollRange() {
        System.out.println(scrollContent.getHeight() - scrollView.getHeight());
        return scrollContent.getHeight() - scrollView.getHeight();
    }
    public ScrollBindHelper bind(VerticalSeekbar seekBar, ObservableScrollView scrollView) {
        ScrollBindHelper helper = new ScrollBindHelper(seekBar, scrollView);
        seekBar.setOnSeekBarChangeListener(helper);
        scrollView.setScrollViewListener(helper);
        return helper;
    }
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (!fromUser) {
            //將拖動的換百分比算成Y值,並對映到SrollView上。
            scrollView.scrollTo(0, progress);
        }
    }
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        isUserSeeking = true;
    }
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        isUserSeeking = false;
    }
    @Override
    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
        showScroll();
        if (isUserSeeking) {
            return;
        }
        //計算當前滑動位置相對於整個範圍的百分比,並對映到SeekBar上
        int range = getContentRange();
        seekBar.setProgress(range != 0 ? range : 0);
    }
    private void showScroll() {
        seekBar.setVisibility(View.VISIBLE);
    }
}

XML

寫完上面那些就可以來設計UI了,在此我使用了兩個自己所設計的元件,分別是com.hr.myapplication3.ObservableScrollView和com.hr.myapplication3.VerticalSeekbar
前面com.hr.myapplication3的部分要根據自己專案的資料夾來做更改

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <com.hr.myapplication3.ObservableScrollView
        android:id="@+id/scrollView"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="15"
        android:scrollbars="none" >
        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="" />
    </com.hr.myapplication3.ObservableScrollView>
    <com.hr.myapplication3.VerticalSeekbar
        android:id="@+id/seekbar"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:progressDrawable="@drawable/seek" />
</LinearLayout>

JAVA程式碼

在回到JAVA程式設計的部分,上述的前置工作都做完以後,終於可以來設計主頁面MainActivity了。
因為將ScrollView和SeekBar邦定的部分都在ScrollBindHelper中做好了,所以不需要在MainActivity多寫甚麼,我們只要宣告ScrollBindHelper並將ScrollView和SeekBar作為參數帶入就可以了。

public class MainActivity extends AppCompatActivity {
    private TextView textView;
    private ScrollBindHelper scrollBindHelper;
    private VerticalSeekbar seekBar;
    private ObservableScrollView scrollView;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.text);
        for(int i = 0;i<99;i++){
            textView.append("第" + i + "行\n");
        }
        seekBar = findViewById(R.id.seekbar);
        scrollView = findViewById(R.id.scrollView);
        scrollBindHelper=new ScrollBindHelper(seekBar,scrollView);
        scrollBindHelper.bind(seekBar,scrollView);
        scrollView.setOnTouchListener(new View.OnTouchListener() {
            private int lastY = 0;
            private int touchEventId = -9983761;
            Handler handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    View scroller = (View) msg.obj;
                    if (msg.what == touchEventId) {
                        if (lastY == scroller.getScrollY()) {
                            handleStop(scroller);
                        } else {
                            handler.sendMessageDelayed(handler.obtainMessage(touchEventId, scroller), 5);
                            lastY = scroller.getScrollY();
                        }
                    }
                }
            };
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    handler.sendMessageDelayed(handler.obtainMessage(touchEventId, v), 5);
                }
                return false;
            }
            private void handleStop(Object view) {
                ScrollView scroller = (ScrollView) view;
                int scrollY = scroller.getScrollY();
                System.out.println("scrollY" + scrollY);
            }
        });
    }
}

成果

圖片


上一篇
[Day21] SeekBar(拖動條)
下一篇
[Day23] 檔案創建
系列文
Android 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言